package lambdasinaction.chap6.my;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 分区 分区是分组的特殊情况：由一个谓词（返回一个布尔值的函数）作为分类函数，它称为“分区函数” 分区函数返回一个布尔值，这意味着得到的分组 Map 的键类型时 Boolean，
 * 于是它最多可以分为两组——true 是一组，false 是一组。
 * 把分区看到分组一种特殊情况。
 * groupingBy 和 partitioningBy 收集器之间的相处之处并不止于此
 * @author Fish
 * @since 0.0.1 2018/7/30 16:46
 */
public class MyPartitioning {

  public static void main(String[] args) {
    // partitionByVegeterian:{false=[pork, beef, chicken, prawns, salmon], true=[french fries, rice, season fruit, pizza]}
//    System.out.println("partitionByVegeterian:" + partitionByVegeterian());
    // 那么通过 Map中键为 true 的值，就可以找出所有的素食菜肴了：
    List<MyDish> vagetarianDishes = partitionByVegeterian().get(false);
    System.out.println(vagetarianDishes);

    List<MyDish> vegetarianDishes2 = MyDish.menu.stream().filter(MyDish::isVegetarian)
        .collect(Collectors.toList());
    System.out.println(vegetarianDishes2);

    // vegetarianDishesByType:{false={FISH=[prawns, salmon], MEAT=[pork, beef, chicken]}, true={OTHER=[french fries, rice, season fruit, pizza]}}
//    System.out.println("vegetarianDishesByType:" + vegetarianDishesByType());

    // mostCaloricPartitionedByVegetarian:{false=pork, true=pizza}
    System.out.println("mostCaloricPartitionedByVegetarian:" + mostCaloricPartitionedByVegetarian());
  }



  /**
   * 例如，如果你是素食者或是请了一位素食的朋友来共进晚餐，可能会想要把菜单按照素食和非素食分开
   */
  private static Map<Boolean, List<MyDish>> partitionByVegeterian() {
    return MyDish.menu.stream().collect(Collectors.partitioningBy(MyDish::isVegetarian));
  }

  /**
   * 对于分区产生的素食和非素食子流，分别按类型对菜肴分组，得到了一个二级 Map, 二级分组得到的结果类似。 分区的好处在于保留了分区函数返回 true 或 false的两套流元素列表。
   */
  private static Map<Boolean, Map<MyDish.MyType, List<MyDish>>> vegetarianDishesByType() {
    return MyDish.menu.stream().collect(
        Collectors.partitioningBy(MyDish::isVegetarian, // 分区函数
            Collectors.groupingBy(MyDish::getType))); // 第二个收集器
  }

  /**
   * 你可以重用前面的代码来找到素食和非素食中热量最高的菜
   * mostCaloricPartitionedByVegetarian:{false=pork, true=pizza}
   * @return
   */
  private static Map<Boolean, MyDish> mostCaloricPartitionedByVegetarian() {
    return MyDish.menu.stream().collect(Collectors.partitioningBy(MyDish::isVegetarian,
        Collectors
            .collectingAndThen(Collectors.maxBy(Comparator.comparingInt(MyDish::getCalories)),
                Optional::get)));
  }

}
